package com.ds.infrastructure.hyperspace.container.flow.handler.route;

import com.ds.infrastructure.hyperspace.common.Container;
import com.ds.infrastructure.hyperspace.common.flow.FlowHandlerPipeline;
import com.ds.infrastructure.hyperspace.container.flow.context.HyperspaceDuplexFlowContext;
import com.ds.infrastructure.hyperspace.container.flow.handler.AbstractPreFlowHandler;
import com.ds.infrastructure.hyperspace.container.internal.operator.OperatorDefinition;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.StringUtils;

import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import static com.ds.infrastructure.hyperspace.container.internal.util.StringConstant.ASTERISK;

/**
 * usage eg:
 *  -   handler: httpRoutePreHandler
 *      handlerParams: [hostName1|hostName1, uri|headerName, (operatorName,operatorArgs)...]
 *
 * @author  Weishaoying
 */
@Slf4j
public class HttpRoutePreFlowHandler extends AbstractPreFlowHandler {

    private static final int INPUT_NAME_INDEX = 1;

    private static final int DEFAULT_HOST_SIZE = 5;

    private volatile boolean allHostMatch;

    private Map<String, String> hostMap = new ConcurrentHashMap<>(DEFAULT_HOST_SIZE);

    private volatile String inputName;

    private volatile List<OperatorDefinition> operatorDefinitionList;

    @Override
    public void handleInput(HyperspaceDuplexFlowContext duplexFlowContext, Object data) {
        if (data != duplexFlowContext.getRequestStartState()) {
            return;
        }

        if (allHostMatch) {
            duplexFlowContext.setRouteMatch(true);
            return;
        }

        if (hostMap.get(duplexFlowContext.getHost()) == null) {
            return;
        }
        if (inputName != null && extractAndComputeInput(duplexFlowContext,
                inputName, operatorDefinitionList) == null) {
            return;
        }
        duplexFlowContext.setRouteMatch(true);
    }

    @Override
    public String handlerName() {
        return "httpRoutePreHandler";
    }

    /**
     *
     * @param container
     * @param handlerParams
     */
    @Override
    public void initHandlerParameters(Container container, FlowHandlerPipeline pipeline, String[] handlerParams) {
        String hostStr = handlerParams[0];
        if (ASTERISK.equals(hostStr)) {
            allHostMatch = true;
            pipeline.registerPipelineHost(ASTERISK);
        } else {
            if (hostStr.indexOf(OR_DELIMITER) == -1) {
                hostMap.put(hostStr, "");
                pipeline.registerPipelineHost(hostStr);
            } else {
                String[] hostStrArray = StringUtils.delimitedListToStringArray(
                        hostStr, OR_DELIMITER);
                for (String tempOneHostStr : hostStrArray) {
                    hostMap.put(tempOneHostStr, "");
                    pipeline.registerPipelineHost(tempOneHostStr);
                }
            }
        }
        if (handlerParams.length > INPUT_NAME_INDEX) {
            inputName = handlerParams[INPUT_NAME_INDEX];
            operatorDefinitionList = parseOperatorDefinition(container, handlerParams, INPUT_NAME_INDEX + 1);
        }

    }

}
